/**
 * @file ring_buf.c
 * @author chushang (email:chushangcs@163.com)
 * @brief 循环缓冲区
 * @version 0.1
 * @date 2025-05-01
 *
 * @copyright Copyright (c) 2025
 *
 */

#include "ring_buf.h"
#include "stdlib.h"
#include "string.h"

/**
 * @brief 初始化循环缓冲区
 *
 * @param buf [in] 指向缓冲区的指针
 * @param buf_size [in] 缓冲区大小
 *
 * @return 动态分配的RingBuf指针
 * @retval NULL 分配失败; 其他: 分配成功
 */
RingBuf *RingBuf_Init(void *buf, uint8_t buf_size)
{
    RingBuf *rb;
    rb = (RingBuf *)malloc(sizeof(RingBuf));
    if (rb == NULL)
    {
        free(rb);
        return NULL;
    }

    if (buf == NULL) // 缓冲区需要动态分配
    {
        rb->buf                   = malloc(buf_size);
        rb->buf_dymanic_allocated = 1;
        if (rb->buf == NULL)
        {
            free(rb->buf);
            free(rb);
            return NULL;
        }
    }
    else // 缓冲区不需要动态分配
    {
        rb->buf                   = buf;
        rb->buf_dymanic_allocated = 0;
    }

    rb->buf_size    = buf_size;
    rb->data_size   = 0;
    rb->read_index  = 0;
    rb->write_index = 0;

    return rb;
}

/* uint8_t RingBuf_GetDataLength(RingBuf *rb)
{
    // 读索引等于写索引时，缓冲区为空
    if (rb->read_index == rb->write_index)
    {
        return 0;
    }
    // 如果缓冲区已满,返回buf_size,牺牲一个空间便于判断是否为满
    if (rb->write_index + 1 == rb->read_index || (rb->write_index == rb->buf_size - 1 && rb->read_index == 0))
    {
        return rb->buf_size;
    }
    // 如果缓冲区未满,返回未处理的数据长度
    if (rb->read_index <= rb->write_index)
    {
        return rb->write_index - rb->read_index;
    }
    else
    {
        return rb->buf_size - rb->read_index + rb->write_index;
    }
} */
// 以上函数可以精简为下面的函数RingBuf_GetDataLength,画图理解

/**
 * @brief 获取缓冲区中有效数据的长度
 *
 * @param rb [in] 指向缓冲区的指针
 * @return 缓冲区中有效数据的长度
 */
uint8_t RingBuf_GetDataLength(RingBuf *rb)
{
    // return (rb->write_index + rb->buf_size - rb->read_index) % rb->buf_size;
    return rb->data_size;
}

/**
 * @brief 获取缓冲区中剩余空间的长度
 *
 * @param rb [in] 指向缓冲区的指针
 * @return 缓冲区中剩余空间的长度
 */
uint8_t RingBuf_GetRemainLength(RingBuf *rb) { return rb->buf_size - RingBuf_GetDataLength(rb); }

/**
 * @brief 向缓冲区中写入数据
 *
 * @param rb     [out] 缓冲区
 * @param data   [in] 待写入的数据指针
 * @param length [in] 写入的长度，字节数
 * @return 写入的长度
 * @retval 0: 空间不足,写入失败; 非0: 写入成功
 */
uint8_t RingBuf_Write(RingBuf *rb, void *data, uint8_t length)
{
    if (RingBuf_GetRemainLength(rb) < length) // 剩余空间不足
    {
        return 0; // 不写入
    }

    // 空间充足
    // 不用分段写入数据,这意味着写完数据时write_index不需要回到缓冲区开头
    if (rb->write_index + length < rb->buf_size)
    {
        memcpy(rb->buf + rb->write_index, data, length);
        rb->write_index = (rb->write_index + length) % rb->buf_size;
    }
    else // 需要分段写入
    {
        uint8_t first_length = rb->buf_size - rb->write_index;
        memcpy(rb->buf + rb->write_index, data, first_length);  // 先写入第一段数据
        memcpy(rb, data + first_length, length - first_length); // 再从头开始写入剩下的数据
        rb->write_index = (length - first_length) % rb->buf_size;
    }
    rb->data_size += length;
    return length;
}

/**
 * @brief 向rb的缓冲区写入一字节数据
 *
 * @param rb   [out] 待被写入数据的缓冲区指针
 * @param data [in]  待写入的数据
 * @return 写入成功或失败：1成功，0失败
 */
uint8_t RingBuf_WriteOne(RingBuf *rb, uint8_t data)
{
    uint8_t *ptr;
    if (RingBuf_GetRemainLength(rb) < 1)
    {
        return 0;
    }
    ptr                  = (uint8_t *)(rb->buf);
    ptr[rb->write_index] = data;
    rb->write_index      = (rb->write_index + 1) % rb->buf_size;
    rb->data_size++;
    return 1;
}

/**
 * @brief 从rb缓冲区读取定长length数据到data中
 *
 * @param rb [in] 缓冲区指针
 * @param data [out] 待写入的指针
 * @param length [in] 数据长度
 * @return 读取的数据长度
 * @retval 0: 读取失败,数据长度不足; 非0: 读取成功
 */
uint8_t RingBuf_Read(RingBuf *rb, void *data, uint8_t length)
{
    if (RingBuf_GetDataLength(rb) < length) // 有效数据长度小
    {
        return 0; // 读取失败
    }

    // 循环读取数据
    // uint8_t *p1 = (uint8_t *)data;
    // uint8_t *p2 = (uint8_t *)(rb->buf);
    // for (uint8_t i = 0; i < length; ++i)
    // {
    //     p1[i] = p2[rb->read_index];
    //     rb->read_index = (rb->read_index + 1) % rb->buf_size;
    // }
    memcpy(data, rb->buf, length);
    rb->read_index = (rb->read_index + length) % rb->buf_size;
    rb->data_size -= length;
    return length;
}

/**
 * @brief 从缓冲区读取一字节数据
 *
 * @param rb   [in]  指向缓冲区的指针
 * @param data [out] 存放数据的指针
 * @return 0：缓冲区无数据；1：读取成功，返回数据
 */
uint8_t RingBuf_ReadOne(RingBuf *rb, uint8_t *data)
{
    uint8_t *ptr;
    if (RingBuf_GetDataLength(rb) < 1)
    {
        return 0;
    }
    ptr            = (uint8_t *)(rb->buf);
    *data          = ptr[rb->read_index];
    rb->read_index = (rb->read_index + 1) % rb->buf_size;
    rb->data_size--;
    return 1;
}
